﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lucene.Net.Store;
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting;
using Lucene.Net.Search;
using Lucene.Net.QueryParsers;

namespace remoting
{
    class Program
    {
        static void Main(string[] args)
        {
            RemoteSearch.Test();

            AppDomain.CreateDomain("Client").DoCallBack(delegate
            {
                Analyzer analyzer = new StandardAnalyzer();
                Query query = new MultiFieldQueryParser(new string[] { "name" }, analyzer).Parse("tom1*");

                // 模拟多次搜索效果。
                for (int x = 0; x < 10; x++)
                {
                    // 获取多个分布搜索对象。
                    RemoteSearchable remoteSearch1 = (RemoteSearchable)RemotingServices.Connect(
                      typeof(RemoteSearchable), "tcp://localhost:800/search");
                    RemoteSearchable remoteSearch2 = (RemoteSearchable)RemotingServices.Connect(
                      typeof(RemoteSearchable), "tcp://localhost:801/search");

                    // 开始搜索。
                    Searchable[] searchables = new Searchable[] { remoteSearch1, remoteSearch2 };
                    Searcher search = new ParallelMultiSearcher(searchables);
                    Sort sort = new Sort(new SortField("age", SortField.STRING, true));
                    Hits hits = search.Search(query, sort);

                    // 显示搜索结果。
                    for (int i = 0; i < hits.Length(); i++)
                    {
                        Document doc = hits.Doc(i);

                        Console.Write("[{0,3}] ", hits.Id(i));
                        foreach (Field field in doc.Fields())
                        {
                            string name = field.Name();
                            string value = doc.Get(name);

                            Console.Write("{0}={1}; ",
                              name,
                              name != "age" ? value : NumberTools.StringToLong(value).ToString());
                        }
                        Console.WriteLine();
                    }

                    //search.Close(); // 调用 Close 会导致分布服务器的 Remoting 对象关闭。
                }
            });
        }
    }

    public static class RemoteSearch
    {
        public static void Test()
        {
            // 利用 AppDomain 模拟多个分布服务器。
            for (int i = 0; i < 2; i++)
            {
                AppDomain server = AppDomain.CreateDomain("Server" + i);
                server.SetData("port", 800 + i);

                server.DoCallBack(delegate
                {
                    Directory directory = new RAMDirectory();
                    Analyzer analyzer = new StandardAnalyzer();
                    Random random = new Random(DateTime.Now.Millisecond);

                    // 创建索引
                    IndexModifier modifier = new IndexModifier(directory, analyzer, true);
                    for (int n = 0; n < 100; n++)
                    {
                        Document doc = new Document();

                        doc.Add(new Field("name", "tom" + random.Next(1, 10),
                          Field.Store.YES, Field.Index.UN_TOKENIZED));
                        doc.Add(new Field("age", NumberTools.LongToString(random.Next(1, 10)),
                          Field.Store.YES, Field.Index.UN_TOKENIZED));
                        doc.Add(new Field("server", AppDomain.CurrentDomain.FriendlyName,
                          Field.Store.YES, Field.Index.NO));

                        modifier.AddDocument(doc);
                    }
                    modifier.Optimize();
                    modifier.Close();

                    // 启动 Remoting。
                    int port = (int)AppDomain.CurrentDomain.GetData("port");
                    TcpServerChannel channel = new TcpServerChannel(port);
                    ChannelServices.RegisterChannel(channel, false);
                    RemotingServices.Marshal(new RemoteSearchable(new IndexSearcher(directory)), "search");
                });
            }
        }
    }
}
